﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using TCCUIControls;

namespace TCCHWLib
{
    public class CommitArbiter
    {
        private Processor m_ProcessorWithToken = null;
        private List<Processor> m_SortedProcessors = null;
        private ListView m_ListView = null;
        private UIArbiter m_UiArbiter = null;

        public UIArbiter UIArbiter
        {
            get { return m_UiArbiter; }
            set { m_UiArbiter = value; }
        }

        public Processor ProcessorWithToken
        {
            get { return m_ProcessorWithToken; }
        }
        public Processor NextProcessor
        {
            get
            {
                lock (m_SortedProcessors)
                    m_SortedProcessors.Sort();

                return (m_SortedProcessors[0].IsCommitReady) ? m_SortedProcessors[0] : null;
            }
        }

        public CommitArbiter()
        {
            m_SortedProcessors = new List<Processor>();
            m_ListView = new ListView();
            m_UiArbiter = new UIArbiter(m_ListView, NextStep, ToggleManualControl);
            UpdateListView();
        }

        public bool HasToken(Processor processor)
        {
            UpdateListView();
            return (processor == m_ProcessorWithToken);
        }
        public void RequestToken(Processor processor)
        {
            Processor next = NextProcessor;
         
            // If the processor is the next to execute & ready,
            // then grant it the arbitration token and
            // signal the processor to commit ...
            //if (m_ProcessorWithToken != null && next == processor)
            if (next == processor)
            {
                m_ProcessorWithToken = next;
                next.Signal();
            }
            else
             {
                processor.Suspend();

                if (next != null)
                    ReleaseToken(next);
            }
            // Else ... add it, and just wait!

            UpdateListView();
        }
        public void ReleaseToken(Processor processor)
        {
            // If the next processor to execute is ready,
            // then grant it the arbitration token and
            // signal the processor to commit ...
            if (NextProcessor != null)
            {
                m_ProcessorWithToken = NextProcessor;
                NextProcessor.Signal();
            }
            else
                // Release the token ...
                m_ProcessorWithToken = null;

            UpdateListView();
        }
        public void WithdrawRequest(Processor processor)
        {
            if (m_SortedProcessors.Contains(processor))
                lock (m_SortedProcessors)
                    m_SortedProcessors.Remove(processor);
        }
        public void AddProcessor(Processor processor)
        {
            lock (m_SortedProcessors)
                m_SortedProcessors.Add(processor);

            UpdateListView();
        }

        private delegate void UpdateListViewDelegate();
        public void UpdateListView()
        {
            if (m_ListView.InvokeRequired)
            {
                m_ListView.BeginInvoke(new UpdateListViewDelegate(UpdateListView));
                return;
            }

            lock (m_SortedProcessors)
            {
                m_SortedProcessors.Sort();
                m_ListView.Items.Clear();

                foreach (Processor p in m_SortedProcessors)
                {
                    if (!m_ListView.Items.ContainsKey(p.ToString()))
                        m_ListView.Items.Add(p.ToString());
                }
            }

        }

        public void NextStep()
        {
            if (!Chip.Instance.IsManuallyControlled)
                return;
            lock (m_SortedProcessors)
            {
                foreach (Processor p in m_SortedProcessors)
                {
                    p.Proceed();
                }
            }
        }
        public void ToggleManualControl()
        {
            Chip.Instance.IsManuallyControlled = !Chip.Instance.IsManuallyControlled;

            if (!Chip.Instance.IsManuallyControlled)
                foreach (Processor p in m_SortedProcessors)
                {
                    p.Proceed();
                }
        }
    }
}
